package netty.bytebuf;

import io.netty.buffer.*;
import io.netty.util.CharsetUtil;
import org.junit.Test;

/**
 * @描述:
 * @创建人: 涂有(tuyou_cd @ keruyun.com)
 * @创建时间: 2019-08-12
 */
public class ByteBufTest {

    /**
     * 堆缓冲
     */
    @Test
    public void heapBuffer() {
        ByteBuf byteBuf = Unpooled.copiedBuffer("tuyou".getBytes());
        if (byteBuf.hasArray()) {  //堆缓冲
            byte[] array = byteBuf.array();
            int offset = byteBuf.arrayOffset() + byteBuf.readerIndex();
            int length = byteBuf.readableBytes();
            System.out.println(new String(array, offset, length));
        }
    }

    /**
     * 直接内存缓冲
     */
    @Test
    public void directBuffer() {
        ByteBuf byteBuf = Unpooled.directBuffer();
        byteBuf.writeBytes("涂有".getBytes());

        if (byteBuf.hasMemoryAddress()) {  //直接内存缓冲
            System.out.println("直接内存缓冲");
            int length = byteBuf.readableBytes();
            byte[] readableBytes = new byte[length];
            byteBuf.getBytes(byteBuf.readerIndex(), readableBytes);
            System.out.println(new String(readableBytes));
        }
    }

    /**
     * 组合缓冲
     * 访问组合缓冲中各个缓冲区
     */
    @Test
    public void compositeBufferTest1() {
        CompositeByteBuf compositeByteBuf = Unpooled.compositeBuffer();
        ByteBuf header = Unpooled.copiedBuffer("header".getBytes());
        ByteBuf body = Unpooled.directBuffer();
        body.writeBytes("body".getBytes());

        compositeByteBuf.addComponents(header, body);
//        compositeByteBuf.removeComponent(0);
        for (int i = 0; i < compositeByteBuf.nioBufferCount(); i++) {
            ByteBuf byteBuf = compositeByteBuf.component(i);
            if (byteBuf.hasArray()) {  //堆缓冲
                byte[] array = byteBuf.array();
                int offset = byteBuf.arrayOffset() + byteBuf.readerIndex();
                int length = byteBuf.readableBytes();
                System.out.println(new String(array, offset, length));
            } else if (byteBuf.hasMemoryAddress()) {  //直接内存缓冲
                int length = byteBuf.readableBytes();
                byte[] readableBytes = new byte[length];
                byteBuf.getBytes(byteBuf.readerIndex(), readableBytes);
                System.out.println(new String(readableBytes));
            }
        }
    }

    /**
     * 组合缓冲
     * 直接访问组合缓冲的全部字节
     */
    @Test
    public void compositeBufferTest2() {
        CompositeByteBuf compositeByteBuf = Unpooled.compositeBuffer();
        ByteBuf header = Unpooled.copiedBuffer("header".getBytes());
        ByteBuf body = Unpooled.directBuffer();
        body.writeBytes("body".getBytes());
        compositeByteBuf.addComponents(header, body);

        int length = header.readableBytes() + body.readableBytes();
//        int length = compositeByteBuf.readableBytes(); //不知为啥返回0，难道是bug？
        byte[] bytes = new byte[length];
        compositeByteBuf.getBytes(compositeByteBuf.readerIndex(), bytes);
        System.out.println(new String(bytes));
    }


    /**
     * 随机访问
     */
    @Test
    public void randomVisit() {
        ByteBuf buf = Unpooled.copiedBuffer("tuyou".getBytes());
        for (int i = 0; i < buf.capacity(); i++) { //capacity表示容量，不像read导致readableBytes的变化
            System.out.println((char)buf.getByte(i));
        }
    }

    /**
     * 丢弃已经读过的字节
     */
    @Test
    public void discardReadBytes() {
        ByteBuf buf = Unpooled.copiedBuffer("tuyou".getBytes());
        System.out.println((char)buf.readByte());
        System.out.println((char)buf.readByte());
        System.out.println((char)buf.readByte());

        System.out.println(buf.readerIndex());
        // 把已经没有读过的内存移动到0并重置readerIndex=0
        // 但是并不会删除已经读过的部分，所以可能导致已读的重新读出来
//        buf.discardReadBytes();
        buf.discardSomeReadBytes();
        System.out.println(buf.readerIndex());
        System.out.println((char)buf.readByte());
        System.out.println((char)buf.readByte());
        System.out.println((char)buf.readByte());
    }

    /**
     * 是否可读
     */
    @Test
    public void isReadable() {
        ByteBuf buf = Unpooled.copiedBuffer("tuyou".getBytes());
        while (buf.isReadable()) {
            System.out.println((char)buf.readByte());
        }
    }

    /**
     * 是否可写
     */
    @Test
    public void isWritable() {
        ByteBuf buf = Unpooled.buffer(10);
        for (int i = 0; buf.isWritable(); i++) {
            buf.writeByte(i + 'A');
        }
        System.out.println(buf.toString(CharsetUtil.UTF_8));
    }

    /**
     * 索引操作
     * markReadIndex()/markWriteIndex()
     * resetReadIndex()/resetWriteIndex  效果同上
     * readIndex()/writeIndex()
     * clear() 同时重置read、write索引，但是并不会真实删除数据，所以clear比discardReadBytes轻量的多
     */
    @Test
    public void mark() {
        ByteBuf buf = Unpooled.directBuffer(100);
        buf.writeBytes("tuyou".getBytes());
        System.out.println((char)buf.readByte());
        System.out.println((char)buf.readByte());
//        buf.readerIndex(0);
//        buf.markReaderIndex();
        buf.resetReaderIndex();
        System.out.println((char)buf.readByte());
        System.out.println((char)buf.readByte());

        buf.writeByte('A');
        buf.writeByte('B');
        buf.resetWriterIndex();
        buf.writeByte('A');
        buf.writeByte('B');
        buf.writeByte('C');
        System.out.println(buf.toString(CharsetUtil.UTF_8));
    }

    /**
     * 查找
     * indexOf
     */
    @Test
    public void search() {
        ByteBuf buf = Unpooled.copiedBuffer("tuyou".getBytes());
//        int index = buf.indexOf(0, buf.capacity(), (byte) 'u');
//        System.out.println(index);

        int i = buf.forEachByte(ByteBufProcessor.FIND_NUL);
        System.out.println(i);
    }

    /**
     * ByteBuf池化：ByteBufAllocator
     */
    @Test
    public void byteBufAllocator() {
        PooledByteBufAllocator pooledByteBufAllocator = PooledByteBufAllocator.DEFAULT;
        ByteBuf buffer = pooledByteBufAllocator.buffer(10);
        buffer.writeBytes("tuyou".getBytes());
        System.out.println(buffer.toString(CharsetUtil.UTF_8));
    }

    /**
     * 引用计数和释放
     */
    @Test
    public void refCnt() {
        ByteBuf buf = Unpooled.copiedBuffer("tuyou".getBytes());
        System.out.println(buf.refCnt());
        System.out.println(buf.toString(CharsetUtil.UTF_8));
        buf.release();
        System.out.println(buf.refCnt());
        System.out.println(buf.toString(CharsetUtil.UTF_8));
    }
}
